package cn.skyclass.net
{
	import cn.skyclass.events.RoEvent;
	import cn.skyclass.events.RpcEvent;
	
	import mx.collections.ArrayCollection;
	import mx.rpc.AbstractOperation;
	import mx.rpc.AsyncToken;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;
	
	
	/**
	 * 使用 RemoteObject 来进行远程调用。
	 * 
	 * 要求：
	 * 1，使用前必需先行调用 RoPool.initChannelSet(uri:String=null):void 来对信道进行初始化。
	 * 2，所有用于在服务器端和客户端之间进行传输数据的对象必需添加 RemoteClass 标签。
	 * 例如：[RemoteClass(alias="cn.skyclass.net.OperationResult")]
	 * 
	 * 事件：
	 * RoEvent.RESULT : 远程调用结束时将发布此事件，事件对象中包含所有的结果信息。
	 * RoEvent.FAULT ：远程调用失败是将发布此事件，事件对象中将包含相应的错误信息。
	 * 
	 * 注：事件 RoEvent.RESULT 与基类 RpcHelper 中的事件 RpcEvent.RPC_RESULT 是等同的，
	 * 他们包含的值以及发布的时机均相同，所以监听这两个事件的结果是等价的。
	 * 另外两个事件 RoEvent.FAULT 与 RpcEvent.RPC_FAULT 也类似。
	 */
	[Event(name="result", type="cn.skyclass.events.RoEvent")]
	[Event(name="fault", type="cn.skyclass.events.RoEvent")]
	public class RoHelper extends RpcHelper
	{
		/**
		 * 实例化一个新实例
		 * 
		 * @ destination : RemoteObject 所对应的 destination
		 * @ resultBeanCla : 远程调用将返回的 bean 类型
		 */
		public function RoHelper(destination:String, resultBeanCla:Class=null){
			this.destination = destination;
			this.resultBeanCla = resultBeanCla;
		}	
		
		protected var destination:String;
		
		/**
		 * 将从此 RoPool 中获取 RemoteObject
		 */
		public var roPool:RoPool = RoPool.getInstance();
		
		
		override protected function loadListResultHandler(e:ResultEvent):void{		
			super.loadListResultHandler(e);
			
			var re:RoEvent = new RoEvent(RoEvent.RESULT);
			re.beansCollection = e.result as ArrayCollection;
			if(!re.beansCollection){
				re.beansCollection = new ArrayCollection();
			}
			re.resultEvent = e;
			dispatchRpcResultEvent(re);
		}		
		
		override protected function getBeanResultHandler(e:ResultEvent):void{		
			super.getBeanResultHandler(e);
			
			var re:RoEvent = new RoEvent(RoEvent.RESULT);
			re.beanData = e.result;
			re.result = re.beanData as OperationResult;
			re.resultEvent = e;
			dispatchRpcResultEvent(re);
		}			
		
		override protected function executeResultHandler(e:ResultEvent):void{		
			super.executeResultHandler(e);
			
			var re:RoEvent = new RoEvent(RoEvent.RESULT);
			re.beanData = e.result;
			re.result = e.result as OperationResult;
			re.resultEvent = e;
			
			if(re.result != null){
				re.result.originalArgs = this.operationArgs;
				this.endExecuteCall(re.result);
			}
			dispatchRpcResultEvent(re);
		}			
		
		
		/**
		 * 执行远程方法的调用。
		 * 使用 RoPool 来统一管理所有的 Remote Object。
		 * 若需要使用自定义的 RO ，则可以仅直接重写这个方法。
		 */				
		override protected function callOperation(resultListener:Function, 
			operationName:String, args:Array):AsyncToken{
			super.callOperation(resultListener, operationName, args);
			
			var ro:RemoteObject = roPool.getRemoteObject(this.destination);
			if(!ro){
				ro = new RemoteObject(this.destination);
				ro.channelSet = roPool.getChannelSet();
				roPool.putRemoteObject(this.destination, ro);
			}

			try{
				ro.requestTimeout = this.requestTimeoutSeconds;
				var opr:AbstractOperation = ro.getOperation(this.operationName);
				opr.arguments = this.operationArgs;
				
				if(!this.useAsyncToken){
					opr.addEventListener(ResultEvent.RESULT, this.operationResultListener);
					opr.addEventListener(FaultEvent.FAULT, this.faultHandler);				
					return opr.send();			
				}else{
					var at:AsyncToken = opr.send();
					at.addResponder(new MyResponder(this.operationResultListener, this.faultHandler));
					return at;
				}
			}catch(e:Error){
				trace(e);
				this.endFaildCall(null, null, e);
			}
			return null;
		}		
		
		
		override protected function dispatchRpcResultEvent(e:RpcEvent):void{
			super.dispatchRpcResultEvent(e);
			
			var ee:RoEvent = new RoEvent(RoEvent.RESULT);
			ee.copyProperties(e);
			dispatchEvent(ee);
		}		
		
		override protected function dispatchRpcFaultEvent(e:RpcEvent):void{
			super.dispatchRpcFaultEvent(e);
			
			var ee:RoEvent = new RoEvent(RoEvent.FAULT);
			ee.copyProperties(e);
			dispatchEvent(ee);
		}
	}
}


	import mx.rpc.IResponder;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;

class MyResponder implements IResponder
{
	public function MyResponder(resultHandler:Function=null, faultHandler:Function=null){
		this.resultHandler = resultHandler;
		this.faultHandler = faultHandler;
	}

	public var resultHandler:Function;
	public var faultHandler:Function;
		
	public function fault(info:Object):void{
		if(info is FaultEvent && faultHandler != null){
			faultHandler(info as FaultEvent);
		}
	}
	
	public function result(data:Object):void{
		if(data is ResultEvent && resultHandler != null){
			resultHandler(data as ResultEvent);
		}
	}
}
